#include <iostream>
#include "ControlUnit.h"
#include "imageloader.h"


// Material Properties
GLfloat cu1_diffuse[] = {0.70, 0.70, 0.70, 1.0};
GLfloat cu2_diffuse[] = {0.60, 0.60, 0.60, 1.0};
GLfloat cu3_diffuse[] = {0.55, 0.55, 0.55, 1.0};
GLfloat cu4_diffuse[] = {0.80, 0.80, 0.80, 1.0};

// Shininess
GLfloat cu_shininess[] = { 21.3 };

ControlUnit::ControlUnit(Map *m)
{
	map = m;
	baseWidth = (GLfloat)1/3;
	baseHeight = (GLfloat)0.75;
	midcubeWidth = (GLfloat)2/3;
	midcubeHeight = (GLfloat)1.5/3;
	midTopWidth = (GLfloat)1.7/3;
	midTopHeight = (GLfloat)1.9/3;
	sizeX = 0;
	sizeZ = 0;
	x = 2;
	y = 0;
	z = 2;
	angle = 0;
	maxHeight = 4.5;		//the maximum height the control unit can go up to
	flagAnimation = 0;
	loadImage();
	currentRobot = 0;

	// CU's spotlight
	cuSpotLight = new spotLight();
	cuSpotLight->setPosition( x+0.5, y, z+0.5);
	cuSpotLight->setDirection(0, -y, 0);
	cuSpotLight->setLightProperty(spotLight::AMBIENT, 0.9, 0.9, 0.9);
	cuSpotLight->setAttenuation(0.000000000000001);
	cuSpotLight->setCutOffAngle(40);


	// camera
	cuCamera.set(cugl::Point(x+4, y+3, z+4), cugl::Point(x+0.5, y, z+0.5), cugl::Vector(0, 1, 0).unit());

	setBoundaries();
}

void ControlUnit::loadImage()
{
	Image* image1 = loadBMP("textures\\gold-texture.bmp");
	goldenTexture = loadTexture(image1);
	delete image1;
}

void ControlUnit::display()
{

	glPushMatrix();
		glMaterialfv(GL_FRONT, GL_SHININESS, cu_shininess);
		glTranslatef(x+0.5, y, z+0.5);
		// draw base blocks x4
		glMaterialfv(GL_FRONT, GL_DIFFUSE, cu1_diffuse);
		glColor3f(0.7,0.7,0.7);
		glPushMatrix();
			for (int i=0; i<2; ++i)
			{
				glPushMatrix();
					glTranslatef(pow(-1.0, i)*baseWidth, (baseHeight*baseWidth)/2, -baseWidth);
					glScalef(1, this->baseHeight, 1);
					glScalef(this->baseWidth, this->baseWidth, this->baseWidth);
					cube();
				glPopMatrix();
			}
			for (int i=0; i<2; ++i)
			{
				glPushMatrix();
					glTranslatef(pow(-1.0, i)*baseWidth, (baseHeight*baseWidth)/2, baseWidth);
					glScalef(1, this->baseHeight, 1);
					glScalef(this->baseWidth, this->baseWidth, this->baseWidth);
					cube();
				glPopMatrix();
			}
		glPopMatrix();

		glMaterialfv(GL_FRONT, GL_DIFFUSE, cu2_diffuse);
		glColor3f(0.6,0.6,0.6);
		glPushMatrix();	
			glTranslatef(0, (GLfloat)(this->midcubeHeight*this->midcubeWidth)/2, 0);
			glScalef(1, this->midcubeHeight, 1);
			glScalef(this->midcubeWidth, this->midcubeWidth, this->midcubeWidth);
			cube();
		glPopMatrix();

		// draw middle-top block
		glMaterialfv(GL_FRONT, GL_DIFFUSE, cu3_diffuse);
		glColor3f(0.55,0.55,0.55);
		glPushMatrix();	
			glTranslatef(0, (GLfloat)(this->midTopHeight*this->midcubeWidth)/2, 0);
			glScalef(1, this->midTopHeight, 1);
			glScalef(this->midTopWidth, this->midTopWidth, this->midTopWidth);
			cube();
		glPopMatrix();

		// draw antena
		glPushMatrix();
			glMaterialfv(GL_FRONT, GL_DIFFUSE, cu4_diffuse);
			glColor3f(0.8,0.8,0.8);
			glTranslatef(0, this->midTopHeight*this->midTopWidth,0);
			glRotatef(-90, 1,0,0);
			GLUquadricObj* quad = gluNewQuadric();
			gluCylinder(quad, 0.015, 0.015, 0.4, 10, 30);
		glPopMatrix();
	glPopMatrix();
}

void ControlUnit::setBoundaries()
{
	sizeX = map->getWidth();
	sizeZ = map->getLength();
}

void ControlUnit::setLocation(GLfloat xAxis, GLfloat yAxis, GLfloat zAxis )
{
	if (xAxis < sizeX  && xAxis > 0 && zAxis < sizeZ && zAxis > 0  && yAxis >= 0)
	{
		this->x = xAxis;
		this->z = zAxis;
		this->y = yAxis;

		// update light position
		cuSpotLight->setPosition( x+0.5, y, z+0.5);
		cuSpotLight->setDirection( 0, -y, 0);

		// update camera positon
		cuCamera.set(cugl::Point(x+2.5, y+6, z+11), cugl::Point(x+0.5, y, z-4.5), cugl::Vector(0, 1, 0).unit());
	}
}

void ControlUnit::cube()
{
	// vertices
	GLfloat A[] = { 0.0f, 1.0f, 1.0f }; 
	GLfloat B[] = { 1.0f, 1.0f, 1.0f }; 
	GLfloat C[] = { 1.0f, 1.0f, 0.0f }; 
	GLfloat D[] = { 0.0f, 1.0f, 0.0f }; 
	GLfloat E[] = { 0.0f, 0.0f, 1.0f }; 
	GLfloat F[] = { 1.0f, 0.0f, 1.0f }; 
	GLfloat G[] = { 1.0f, 0.0f, 0.0f }; 
	GLfloat H[] = { 0.0f, 0.0f, 0.0f }; 

	// texture coordinates
	GLfloat bottomLeft[] = {0.0f, 0.0f};
	GLfloat bottomRight[] = {3.0f, 0.0f};
	GLfloat topLeft[] = {0.0f, 3.0f};
	GLfloat topRight[] = {3.0f, 3.0f};


	glPushMatrix();

		glBindTexture(GL_TEXTURE_2D, goldenTexture);
		glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
		glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);

		glTranslatef(-0.5, -0.5, -0.5);

		// top
		glBegin(GL_QUADS);
			glNormal3f( 0.0, 1.0, 0.0);
			glTexCoord2fv(bottomLeft);
			glVertex3fv(A);
			glTexCoord2fv(bottomRight);
			glVertex3fv(B);
			glTexCoord2fv(topRight);
			glVertex3fv(C);
			glTexCoord2fv(topLeft);
			glVertex3fv(D);
		glEnd();

		// bottom
		glBegin(GL_QUADS);
			glNormal3f( 0.0, -1.0, 0.0);
			glTexCoord2fv(bottomLeft);
			glVertex3fv(H);
			glTexCoord2fv(bottomRight);
			glVertex3fv(G);
			glTexCoord2fv(topRight);
			glVertex3fv(F);
			glTexCoord2fv(topLeft);
			glVertex3fv(E);
		glEnd();

		// Front
		glBegin(GL_QUADS);
			glNormal3f( 0.0, 0.0, 1.0);
			glTexCoord2fv(bottomLeft);
			glVertex3fv(E);
			glTexCoord2fv(bottomRight);
			glVertex3fv(F);
			glTexCoord2fv(topRight);
			glVertex3fv(B);
			glTexCoord2fv(topLeft);
			glVertex3fv(A);
		glEnd();

		// back
		glBegin(GL_QUADS);
			glNormal3f( 0.0, 0.0, -1.0);
			glTexCoord2fv(bottomLeft);
			glVertex3fv(G);
			glTexCoord2fv(bottomRight);
			glVertex3fv(H);
			glTexCoord2fv(topRight);
			glVertex3fv(D);
			glTexCoord2fv(topLeft);
			glVertex3fv(C);
		glEnd();

		// left
		glBegin(GL_QUADS);
			glNormal3f( -1.0, 0.0, 0.0);
			glTexCoord2fv(bottomLeft);
			glVertex3fv(H);
			glTexCoord2fv(bottomRight);
			glVertex3fv(E);
			glTexCoord2fv(topRight);
			glVertex3fv(A);
			glTexCoord2fv(topLeft);
			glVertex3fv(D);
		glEnd();

		// right
		glBegin(GL_QUADS);
			glNormal3f( 1.0, 0.0, 0.0);
			glTexCoord2fv(bottomLeft);
			glVertex3fv(F);
			glTexCoord2fv(bottomRight);
			glVertex3fv(G);
			glTexCoord2fv(topRight);
			glVertex3fv(C);
			glTexCoord2fv(topLeft);
			glVertex3fv(B);
		glEnd();

	glPopMatrix();
}

void ControlUnit::move(GLfloat xAxis, GLfloat yAxis, GLfloat zAxis)
{
	if(!currentRobot)
	{
		int idEnemy = map->moveControlUnit(xAxis, yAxis, zAxis);
		if(!idEnemy)
		{
			x = xAxis;
			y = yAxis;
			z = zAxis;
		}
		else if(idEnemy > -1)
		{
			if(!(*mapRobots)[idEnemy]->isRandom())
				currentRobot = (*mapRobots)[idEnemy];
			x = xAxis;
			y = yAxis;
			z = zAxis;
		}
	}
	else
	{
		if(currentRobot->move(xAxis, 0, zAxis))
		{
			x = xAxis;
			y = yAxis;
			z = zAxis;
		}
	}
}

Robot* ControlUnit::getCurrentRobot()
{
	return currentRobot;
}

bool ControlUnit::onRobot()
{
	return currentRobot;
}
bool ControlUnit::onBuilding()
{
	return false;
}


void ControlUnit::moveForward()
{
	//setLocation(x + sin(angle), y, z + cos(angle));
	if(currentRobot)
	{
		angle = currentRobot->getAngle();
		if(angle == 0)
			move(x, y, z - 1);
		else if(angle == 90)
			move(x - 1, y, z);
		else if(angle == 180)
			move(x, y, z + 1);
		else
			move(x + 1, y, z);
	}
	else
		move(x, y, z + 1);
	
}

void ControlUnit::moveBackward()
{
	if(currentRobot)
	{
		angle = currentRobot->getAngle();
		if(angle == 0)
			move(x, y, z + 1);
		else if(angle == 90)
			move(x + 1, y, z);
		else if(angle == 180)
			move(x, y, z - 1);
		else
			move(x - 1, y, z);
	}
	else
		move(x, y, z - 1);
}

void ControlUnit::moveLeft()
{
	if(!currentRobot)
		move(x + 1, y, z);
	else
	{
		currentRobot->rotate(-90);
	}
}

void ControlUnit::moveRight()
{
	if(!currentRobot)
		move(x - 1, y, z);
	else
	{
		currentRobot->rotate(90);
	}
}

void ControlUnit::moveUp()
{
	if(y < maxHeight)
	{
		move(x, y +0.1, z);
		flagAnimation = 0;
	}else {
		move(x, maxHeight, z);
		flagAnimation = 0;
	}
}

void ControlUnit::moveDown()
{
	if(y > 0)
	{
		move(x, y - 0.1, z);
		flagAnimation = 0;	
	}else
	{
		move(x, 0, z);
		flagAnimation = 0;
	}

}

void ControlUnit::detach()
{
	if(onRobot())
	{
		currentRobot = 0;
		moveUp();
	}
}
void ControlUnit::animate()
{
	++flagAnimation;
	if(flagAnimation > 5)
		setLocation(x, y, z);
}

void ControlUnit::setMapRobots(std::map<int, Robot*> *mcu)
{
	mapRobots = mcu;
}

cugl::Camera* ControlUnit::getCamera()
{
	return &cuCamera;
}

spotLight* ControlUnit::getLight()
{
	return this->cuSpotLight;
}

void ControlUnit::setID(int i)
{
	id = i;
}

int ControlUnit::getID()
{
	return id;
}

int ControlUnit::getX()
{
	return x;
}
int ControlUnit::getY()
{
	return y;
}
int ControlUnit::getZ()
{
	return z;
}

ControlUnit::~ControlUnit(void)
{
	delete cuSpotLight;
	currentRobot = 0;
}
